home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FM Towns: Free Software Collection 9
/
FM Towns Free Software Collection 9.iso
/
t_os
/
tool
/
extdrv
/
src
/
buf_fat.c
next >
Wrap
C/C++ Source or Header
|
1994-11-16
|
7KB
|
311 lines
#include "extdrv.h"
#include "file.h"
#include "dir.h"
#include "buffer.h"
#include "dos.h"
#include "extern.h"
int n_fatbuf;
struct fatbuf far *fat_base = NULL, far *fat_head = NULL, far *fat_tail = NULL;
struct pbuf far *pfatbuf;
struct fatbuf far *get_fat(struct drvinfo far *d, u_long offset)
{
int n;
u_short off, sector;
u_long sec;
u_long addr;
struct fatbuf far *p, far *free;
free = NULL;
off = (u_short)(offset >> 11);
for (p = fat_head; p != NULL; p = p->next){
if (p->drv == d && p->off == off){
if (p != fat_head){
if ((p->prev->next = p->next) == NULL)
fat_tail = p->prev;
else
p->next->prev = p->prev;
p->next = fat_head;
p->prev = NULL;
fat_head->prev = p;
fat_head = p;
}
return (p);
}
if (p->drv == NULL)
free = p;
}
#ifdef DEBUG_FAT
auxputs(" FAT miss hit ");
auxprinthex(off);
auxputs(" ");
#endif
if (free == NULL){
#ifdef DEBUG_FAT
auxputs(" exhausted ");
#endif
p = fat_tail;
if (p->pp != NULL){
if (p->pp->dirty){
addr = p->buf + (p->pp->offset << LOGPBUFSIZ);
xcopy(laddr(p->pp->data), addr, PBUFSIZE);
p->dirty = TRUE;
}
p->pp->drv = NULL; /* invalidate */
p->pp = NULL;
}
if (p->dirty){
#ifdef DEBUG_FAT
auxputs("flush FBUF#");
auxprinthex((u_long)((char far *)p - (char far *)fat_base)/sizeof (struct fatbuf));
auxputs(" ");
auxprinthex(p->off);
auxputs(" ");
auxprinthex(p->n_entry);
auxputs(" ");
#endif
d = p->drv;
sector = FATBUFSIZ / d->sectsiz;
sector = d->fat_off + p->off * sector;
if (write2(d, (u_long)sector, FATBUFSIZ/d->blocksize, p->buf) != 0){
#ifdef DEBUG_ERR
auxputs("write error ");
#endif
return (NULL);
}
if (!d->fat_error){
#ifdef DEBUG_FAT
auxputs("dup fat ");
#endif
n = d->n_fat - 1;
sec = (u_long)sector;
while (--n >= 0){
sec += d->fatsiz;
if (write2(d, sec, FATBUFSIZ/d->blocksize, p->buf) != 0){
#ifdef DEBUG_ERR
auxputs("write error ");
#endif
return (NULL);
}
}
}
#ifdef DEBUG_ERR
else {
auxputs("FAT no-dup, because of fat_error\r\n");
}
#endif
p->dirty = FALSE;
}
fat_tail = p->prev;
p->prev->next = NULL;
fat_head->prev = p;
p->next = fat_head;
p->prev = NULL;
fat_head = p;
} else {
if ((p = free) != fat_head){
if (p->next == NULL)
fat_tail = p->prev;
else
p->next->prev = p->prev;
p->prev->next = p->next;
fat_head->prev = p;
p->next = fat_head;
p->prev = NULL;
fat_head = p;
}
}
p->drv = d;
p->off = off;
if (off == d->fat_last_sec)
p->n_entry = d->fat_last_size;
else
p->n_entry = FATBUFSIZ;
sector = FATBUFSIZ / d->sectsiz;
sector = d->fat_off + off * sector;
if (read2(d, (u_long)sector, FATBUFSIZ/d->blocksize, p->buf) != 0){
#ifdef DEBUG
auxputs("read error ");
#endif
p->drv = NULL;
return (NULL);
}
#ifdef DEBUG_FAT
auxputs("FBUF#");
auxprinthex((u_long)((char far *)p - (char far *)fat_base)/sizeof (struct fatbuf));
auxputs(" DISK-READ,");
auxprinthex(sector);
auxputs(",");
auxprinthex(p->n_entry);
auxputs(" ");
#endif
return (p);
}
fat_flush(struct drvinfo far *d, int invalidate)
{
struct fatbuf far *p;
int n;
u_short sector;
u_long sec;
u_long addr;
#ifdef DEBUG
auxputs("flush_fat ");
#endif
for (p = fat_head; p != NULL; p = p->next){
if (d == NULL || p->drv == d){
if (p->pp != NULL && p->pp->dirty){
addr = p->buf + (p->pp->offset << LOGPBUFSIZ);
xcopy(laddr(p->pp->data), addr, PBUFSIZE);
p->pp->dirty = FALSE;
p->dirty = TRUE;
}
if (p->dirty){
#ifdef DEBUG
auxputs("dirty ");
#endif
d = p->drv;
sector = FATBUFSIZ / d->sectsiz;
sector = d->fat_off + p->off * sector;
if (write2(d, (u_long)sector, FATBUFSIZ/d->blocksize,
p->buf) != 0){
#ifdef DEBUG_ERR
auxputs("write error ");
#endif
return (-1);
}
if (!p->drv->fat_error){
n = p->drv->n_fat - 1;
sec = (u_long)sector;
while (--n >= 0){
sec += d->fatsiz;
if (write2(d, sec, FATBUFSIZ/d->blocksize,
p->buf) != 0){
#ifdef DEBUG_ERR
auxputs("write error ");
#endif
return (-1);
}
}
}
#ifdef DEBUG_ERR
else {
auxputs("FAT no-dup, because of fat_error\r\n");
}
#endif
p->dirty = FALSE;
}
if (invalidate){
if (p->pp != NULL){
p->pp->drv = NULL;
p->pp = NULL;
}
p->drv = NULL;
}
}
}
#ifdef DEBUG
auxputs("done.\r\n");
#endif
return (0);
}
inv_fat(u_int devno)
{
struct fatbuf far *p;
for (p = fat_head; p != NULL; p = p->next){
if (p->drv->devno == devno){
if (p->pp != NULL){
p->pp->drv = NULL;
p->pp = NULL;
}
p->dirty = FALSE;
p->drv = NULL;
}
}
return (0);
}
static struct pbuf far *get_pfatbuf(struct drvinfo far *d, long offset)
{
int i;
struct pbuf far *pp;
struct fatbuf far *p;
u_long addr;
u_short off, offp;
/* search primary buffer */
off = (u_short)(offset >> LOGFATBUFSIZ);
offp = (u_short)(offset >> LOGPBUFSIZ) & (NFATPBUF - 1);
for (i = 0, pp = pfatbuf; i < 2; i++, pp++)
if (pp->drv==d && pp->id==off)
break;
if (i == 2 || offp != pp->offset){
if (i == 2){ /* not found */
pp = pfatbuf;
if (pp->age == 0)
pp++;
if (pp->drv != NULL){
if (pp->dirty){
p = pp->buffer.fbuf;
addr = p->buf + (pp->offset << LOGPBUFSIZ);
xcopy(laddr(pp->data), addr, PBUFSIZE);
p->dirty = TRUE;
}
pp->buffer.fbuf->pp = NULL;
}
if ((p = get_fat(d, offset)) == NULL){
#ifdef DEBUG
auxputs("fat_read: error\r\n");
#endif
pp->drv = NULL;
return (NULL);
}
pp->drv = d;
pp->id = off;
pp->buffer.fbuf = p;
pp->buffer.fbuf->pp = pp;
} else {
p = pp->buffer.fbuf;
if (pp->dirty){
addr = p->buf + (pp->offset << LOGPBUFSIZ);
xcopy(laddr(pp->data), addr, PBUFSIZE);
p->dirty = TRUE;
}
}
pp->offset = offp;
addr = p->buf + (offp << LOGPBUFSIZ);
xcopy(addr, laddr(pp->data), PBUFSIZE);
pp->dirty = FALSE;
}
pp->age = 0;
if (pp == pfatbuf)
(pfatbuf+1)->age = 1;
else
pfatbuf->age = 1;
return (pp);
}
u_short fat_read(struct drvinfo far *d, long offset)
{
struct pbuf far *pp;
if ((pp = get_pfatbuf(d, offset)) == NULL)
return (1);
return (*(u_short far *)(pp->data + (offset & (PBUFSIZE - 1))));
}
fat_write(struct drvinfo far *d, long offset, u_short fat)
{
struct pbuf far *pp;
if ((pp = get_pfatbuf(d, offset)) == NULL)
return (1);
pp->dirty = TRUE;
*(u_short far *)(pp->data + (offset & (PBUFSIZE - 1))) = fat;
return (0);
}